﻿using System;
using System.Text;
using System.Linq;
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore;

namespace Admin.CYT369.Com.DAL.Services
{
    /// <summary>
    /// 系统服务
    /// </summary>
    public class AppService : Admin.CYT369.Com.DAL.DbContexts.BaseService<AppService>
    {
        public AppService() { }

        #region AppPlugs
        public IQueryable<Admin.CYT369.Com.DAL.Domains.Apps.AppPlugs> GetAppPlugs(bool? enable = null)
        {
            var query = base.Get<Admin.CYT369.Com.DAL.Domains.Apps.AppPlugs>();
            if (enable.HasValue)
            {
                query = query.Where(c => c.Enable == enable.Value);
            }

            return query;
        }

        public IQueryable<Admin.CYT369.Com.DAL.Domains.Apps.AppPlugs> GetAppPlugs(int page, int rows, ref int total, string plugName = null)
        {
            var items = this.Get<Admin.CYT369.Com.DAL.Domains.Apps.AppPlugs>();

            if (!string.IsNullOrEmpty(plugName))
            {
                items = items.Where(c => c.PlugsName.Contains(plugName));
            }

            return items;
        }

        public Admin.CYT369.Com.DAL.Domains.Apps.AppPlugs GetAppPlugsByID(int id)
        {
            return this.GetOne<Admin.CYT369.Com.DAL.Domains.Apps.AppPlugs>(c => c.Id == id);
        }

        public bool DeleteAppPlugs(int id)
        {
            return this.Delete<Admin.CYT369.Com.DAL.Domains.Apps.AppPlugs>(c => c.Id == id);
        }

        public bool SaveAppPlugs(Admin.CYT369.Com.DAL.Domains.Apps.AppPlugs appPlugs)
        {
            return this.Save<Admin.CYT369.Com.DAL.Domains.Apps.AppPlugs>(appPlugs, c => c.Id == appPlugs.Id);
        }
        #endregion

        #region GetAppLogs
        public IQueryable<Admin.CYT369.Com.DAL.Domains.Apps.AppLog> GetAppLogs(int page, int rows, ref int total,
                                                                        DateTime? dateFrom = null, DateTime? dateTo = null,
                                                                        string logSource = null, string model = null,
                                                                        int? logTypeId = null)
        {

            var items = this.Get<Admin.CYT369.Com.DAL.Domains.Apps.AppLog>();
            if (logTypeId.HasValue)
            {
                items = items.Where(c => c.LogTypeID == logTypeId.Value);
            }

            if (dateFrom.HasValue)
            {
                items = items.Where(c => c.LogTime >= dateFrom.Value);
            }

            if (dateTo.HasValue)
            {
                dateTo = new DateTime(dateTo.Value.Year, dateTo.Value.Month, dateTo.Value.Day, 23, 59, 59);
                items = items.Where(c => c.LogTime <= dateTo);
            }

            if (!string.IsNullOrEmpty(model))
            {
                items = items.Where(c => c.Model.Contains(model));
            }

            if (!string.IsNullOrEmpty(logSource))
            {
                items = items.Where(c => c.LogSource.Contains(logSource));
            }

            return this.Pagination(page, rows, ref total, items, c => c.LogTime);
        }

        public Admin.CYT369.Com.DAL.Domains.Apps.AppLog GetAppLogByID(long id)
        {
            return this.GetOne<Admin.CYT369.Com.DAL.Domains.Apps.AppLog>(c => c.Id == id);
        }

        public bool SaveAppLog(Admin.CYT369.Com.DAL.Domains.Apps.AppLog item)
        {
            try
            {
                return this.Save<Admin.CYT369.Com.DAL.Domains.Apps.AppLog>(item);
            }
            catch (Exception ex)
            {
                try
                {
                    string path = new System.IO.FileInfo(System.Reflection.Assembly.GetEntryAssembly().Location).DirectoryName;
                    path = System.IO.Path.Combine(path, "logs");
                    if (!System.IO.Directory.Exists(path))
                    {
                        System.IO.Directory.CreateDirectory(path);
                    }

                    path = System.IO.Path.Combine(path, string.Format("{0}.log", DateTime.Now.ToString("yyyyMMddhhmmss")));

                    var sb = new System.Text.StringBuilder();
                    var exception = ex;
                    while (exception != null)
                    {
                        sb.AppendFormat("{0}\r\n{1}", exception.Message, exception.StackTrace);
                        exception = exception.InnerException;
                        if (exception != null)
                        {
                            sb.Append("\r\n\r\n");
                        }
                    }

                    System.IO.File.WriteAllText(path, sb.ToString());
                }
                catch { }
            }

            return false;
        }

        public bool SaveAppLog(Admin.CYT369.Com.DAL.Enums.SystemLogTypeEnum logtype, string source, string model, string message, string detail, string client = null, string remoteIP = null)
        {
            var log = new Admin.CYT369.Com.DAL.Domains.Apps.AppLog()
            {
                LogTypeID = (int)logtype,
                LogSource = source,
                Model = model,
                LogDetails = detail,
                LogMessage = message,
                LogTime = DateTime.Now,
                Client = client,
                RemoteIP = remoteIP
            };

            return this.SaveAppLog(log);
        }

        public bool SaveAppLog(string source, string model, System.Exception ex, string client = null, string remoteIP = null)
        {
            if (ex != null)
            {
                var detail = new System.Text.StringBuilder();
                var exception = ex;
                while (exception != null)
                {
                    detail.AppendFormat("{0}\r\n{1}", exception.Message, exception.StackTrace);
                    exception = exception.InnerException;
                    if (exception != null)
                    {
                        detail.Append("\r\n\r\n");
                    }
                }

                var log = new Admin.CYT369.Com.DAL.Domains.Apps.AppLog()
                {
                    LogTypeID = (int)Admin.CYT369.Com.DAL.Enums.SystemLogTypeEnum.ERROR,
                    LogSource = source,
                    Model = model,
                    LogMessage = ex.Message,
                    LogDetails = detail.ToString(),
                    Client = client,
                    RemoteIP = remoteIP,
                    LogTime = DateTime.Now
                };

                return this.SaveAppLog(log);
            }

            return false;
        }

        public bool SaveAppLog(string source, System.Exception ex, string clientIP = null, string remoteIP = null)
        {
            return this.SaveAppLog(source, null, ex, clientIP, remoteIP);
        }
        #endregion

        #region system menus
        public IEnumerable<Admin.CYT369.Com.DAL.Domains.Apps.SystemMenu> GetAllMenus(bool? enable = null, int? userId = null)
        {
            var db = this.Ctx;
            var menus = from o in db.Set<Admin.CYT369.Com.DAL.Domains.Apps.SystemMenu>()
                        where o.Deleted == false
                        select o;

            if (enable.HasValue)
            {
                menus = menus.Where(c => c.Enable == enable.Value);
            }

            if (userId.HasValue)
            {
                var userRoles = from o in db.Set<Admin.CYT369.Com.DAL.Domains.sys.UserRole>()
                                where o.UserId == userId
                                select o.RoleId;

                var roleMenuIds = from o in userRoles
                                  join r in db.Set<Admin.CYT369.Com.DAL.Domains.Apps.RoleMenu>() on o equals r.RoleID
                                  where r.Status > 0
                                  select r.MenuID;

                var result = from o in menus
                             join m in roleMenuIds on o.Id equals m
                             select o;

                var array = result.Distinct().ToArray();

                return array.OrderBy(c => c.Sequence).ToArray();
            }

            return menus.OrderBy(c => c.Sequence).ToArray();
        }

        public IEnumerable<Admin.CYT369.Com.DAL.Domains.Apps.SystemMenu> GetMenus(int? parentId = null, bool? enable = null, int? userId = null)
        {
            var db = this.Ctx;
            IQueryable<Admin.CYT369.Com.DAL.Domains.Apps.SystemMenu> menus = null;
            if (parentId.HasValue)
            {
                menus = from o in db.Set<Admin.CYT369.Com.DAL.Domains.Apps.SystemMenu>()
                        where o.Deleted ==false && o.ParentID == parentId.Value
                        select o;
            }
            else
            {
                menus = from o in db.Set<Admin.CYT369.Com.DAL.Domains.Apps.SystemMenu>()
                        where o.Deleted == false && o.ParentID == 0
                        select o;
            }

            if (enable.HasValue)
            {
                menus = menus.Where(c => c.Enable == enable.Value);
            }

            if (userId.HasValue)
            {
                var userRoles = from o in db.Set<Admin.CYT369.Com.DAL.Domains.sys.UserRole>()
                                where o.UserId == userId
                                select o.RoleId;

                var roleMenuIds = from o in userRoles
                                  join r in db.Set<Admin.CYT369.Com.DAL.Domains.Apps.RoleMenu>() on o equals r.RoleID
                                  where r.Status > 0
                                  select r.MenuID;

                var result = from o in menus
                             join m in roleMenuIds on o.Id equals m
                             select o;

                var array = result.Distinct().ToArray();

                return array.OrderBy(c => c.Sequence).ToArray();
            }

            return menus.OrderBy(c => c.Sequence).ToArray();
        }

        public IEnumerable<Admin.CYT369.Com.DAL.Domains.Apps.SystemMenu> GetSubMenus(int parentId = 0, bool? enable = null, int? userId = null)
        {
            var db = this.Ctx;
            var menus = from o in db.Set<Admin.CYT369.Com.DAL.Domains.Apps.SystemMenu>()
                        where o.ParentID == parentId && o.Deleted == false
                        select o;

            if (enable.HasValue)
            {
                menus = menus.Where(c => c.Enable == enable.Value);
            }


            foreach (var m in menus)
            {
                foreach (var sm in GetSubMenus(m.Id, enable, userId))
                {
                    m.SubMenus.Add(sm);
                }
            }

            if (userId.HasValue)
            {
                var userRoles = from o in db.Set<Admin.CYT369.Com.DAL.Domains.sys.UserRole>()
                                where o.UserId == userId
                                select o.RoleId;

                var roleMenuIds = from o in userRoles
                                  join r in db.Set<Admin.CYT369.Com.DAL.Domains.Apps.RoleMenu>() on o equals r.RoleID
                                  where r.Status > 0
                                  select r.MenuID;

                var result = from o in menus
                             join m in roleMenuIds on o.Id equals m
                             select o;

                var array = result.Distinct().ToArray();

                return array.OrderBy(c => c.Sequence).ToArray();
            }

            return menus.OrderBy(c => c.Sequence);
        }

        public List<Admin.CYT369.Com.DAL.Domains.Apps.SystemMenu> GetMenuTree(int parentId = 0, int? not_id = null, bool? enable = null, bool? needIcon = null)
        {
            var list = new List<Admin.CYT369.Com.DAL.Domains.Apps.SystemMenu>();
            if (!not_id.HasValue) { not_id = 0; }

            var menus = this.Get<Admin.CYT369.Com.DAL.Domains.Apps.SystemMenu>(c => c.ParentID == parentId && c.Deleted == false && c.Id != not_id.Value);

            foreach (var m in menus.OrderBy(c=>c.Sequence))
            {
                m.SubMenus = GetMenuTree(m.Id, not_id, enable);
                if (needIcon == false)
                {
                    m.IconClassName = null;
                }
                m.state = m.SubMenus.Count > 0 ? "closed" : "open";
                list.Add(m);
            }

            return list;
        }

        public Admin.CYT369.Com.DAL.Domains.Apps.SystemMenu GetAppMenuByID(int id, bool includeSubMenu = false)
        {
            if (includeSubMenu)
            {
                return this.GetOne<Admin.CYT369.Com.DAL.Domains.Apps.SystemMenu, ICollection<Admin.CYT369.Com.DAL.Domains.Apps.SystemMenu>>(d => d.SubMenus, c => c.Id == id);
            }
            else
            {
                return this.GetOne<Admin.CYT369.Com.DAL.Domains.Apps.SystemMenu>(c => c.Id == id);
            }
        }

        public bool SaveAppMenu(Admin.CYT369.Com.DAL.Domains.Apps.SystemMenu menu)
        {
            return this.Save<Admin.CYT369.Com.DAL.Domains.Apps.SystemMenu>(menu, c => c.Id == menu.Id);
        }

        public bool DeleteAppMenu(int id)
        {
            return this.DoAction<Admin.CYT369.Com.DAL.Domains.Apps.SystemMenu>(c => c.Id == id, delegate (Admin.CYT369.Com.DAL.Domains.Apps.SystemMenu menu)
            {
                menu.Enable = false;
                menu.Deleted = true;
            });
        }
        #endregion

        #region 操作权限
        public IQueryable<Admin.CYT369.Com.DAL.Domains.Apps.AppOperation> GetAppOperations(int page, int rows, ref int total)
        {
            var items = this.Get<Admin.CYT369.Com.DAL.Domains.Apps.AppOperation>(c => c.Deleted == false);
            return this.Pagination(page, rows, ref total, items, c => c.Id);
        }

        public Admin.CYT369.Com.DAL.Domains.Apps.AppOperation GetAppOperationByID(int id)
        {
            return this.GetOne<Admin.CYT369.Com.DAL.Domains.Apps.AppOperation>(c => c.Deleted == false && c.Id == id);
        }

        public bool SaveAppOperation(Admin.CYT369.Com.DAL.Domains.Apps.AppOperation operation)
        {
            return this.Save<Admin.CYT369.Com.DAL.Domains.Apps.AppOperation>(operation, c => c.Deleted == false && c.Id == operation.Id);
        }

        public bool DeleteAppOperation(int id)
        {
            return base.DoAction<Admin.CYT369.Com.DAL.Domains.Apps.AppOperation>(c => c.Id == id, delegate (Admin.CYT369.Com.DAL.Domains.Apps.AppOperation op) {
                op.Deleted = true;
            });
        }

        #endregion

        #region SystemMenuOperation
        public IQueryable<Admin.CYT369.Com.DAL.Domains.Apps.SystemMenuOperation> GetSystemMenuOperations(int menuId)
        {
            return base.Get<Admin.CYT369.Com.DAL.Domains.Apps.SystemMenuOperation>(c => c.MenuID == menuId).OrderBy(c => c.Id);
        }

        /// <summary>
        /// 保存菜单功能权限
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        public bool SaveSystemMenuOperation(Admin.CYT369.Com.DAL.Domains.Apps.SystemMenuOperation item)
        {
            using (var db = this.Ctx)
            {
                var exist = db.Set<Admin.CYT369.Com.DAL.Domains.Apps.SystemMenuOperation>().Where(c => c.MenuID == item.MenuID && c.OperationID == item.OperationID).FirstOrDefault(); ;
                if (item.Enable)
                {
                    if (exist == null)
                    {
                        db.Set<Admin.CYT369.Com.DAL.Domains.Apps.SystemMenuOperation>().Add(item);
                    }
                }
                else
                {
                    if (exist != null)
                    {
                        db.Set<Admin.CYT369.Com.DAL.Domains.Apps.SystemMenuOperation>().Remove(exist);
                        db.Set<Admin.CYT369.Com.DAL.Domains.Apps.RoleMenuOperation>().RemoveRange(db.Set<Admin.CYT369.Com.DAL.Domains.Apps.RoleMenuOperation>().Where(c => c.OperationID == exist.OperationID));
                    }
                }

                db.SaveChanges();

                return true;
            }
        }

        /// <summary>
        /// 保存批量信息
        /// </summary>
        /// <param name="items"></param>
        /// <returns></returns>
        public bool SaveSystemMenuOperationList(List<Admin.CYT369.Com.DAL.Domains.Apps.SystemMenuOperation> items)
        {
            using (var db = this.Ctx)
            {
                foreach (var item in items)
                {
                    var exist = db.Set<Admin.CYT369.Com.DAL.Domains.Apps.SystemMenuOperation>().Where(c => c.MenuID == item.MenuID && c.OperationID == item.OperationID).FirstOrDefault(); ;
                    if (item.Enable)
                    {
                        if (exist == null)
                        {
                            db.Set<Admin.CYT369.Com.DAL.Domains.Apps.SystemMenuOperation>().Add(item);
                        }
                    }
                    else
                    {
                        if (exist != null)
                        {
                            db.Set<Admin.CYT369.Com.DAL.Domains.Apps.SystemMenuOperation>().Remove(exist);
                            db.Set<Admin.CYT369.Com.DAL.Domains.Apps.RoleMenuOperation>().RemoveRange(db.Set<Admin.CYT369.Com.DAL.Domains.Apps.RoleMenuOperation>().Where(c => c.OperationID == exist.OperationID));
                        }
                    }
                }

                db.SaveChanges();

                return true;
            }
        }
        #endregion


    }
}
